#include "softpwmitem.h"


#define NEXT_POINT_MIN_LIMIT 10  //包含 下限和上限，10, period - 10

SoftPwmItem::SoftPwmItem()
{
}

SoftPwmItem::~SoftPwmItem()
{
}

void SoftPwmItem::AttachGpio(const GpioPortPin &gpio, const GpioPortPin &gpioN)
{
    Port = gpio;
    PortN = gpioN;
}

void SoftPwmItem::DettachGpio()
{
    Port = GpioPortPin::None();
    PortN = GpioPortPin::None();
}

void SoftPwmItem::Update()
{
    if(Duty > 100)
        Duty = 100;
    if(Duty < 0)
        Duty = 0;
        
    if(Duty == 0)
    {
        CalcT1 = 0;
        CalcT2 = Period;
        IsFullOutMode = true;
    }
    else if(Duty == 100)
    {
        CalcT1 = Period;
        CalcT2 = 0;
        IsFullOutMode = true;
    }
    else 
    {
        CalcT1 = (Duty/ 100.0) * Period; 
        CalcT2 = Period - CalcT1;
        //limit the duty
        if(NEXT_POINT_MIN_LIMIT > 0)
        {
            if(CalcT1 < NEXT_POINT_MIN_LIMIT)
                CalcT1 = NEXT_POINT_MIN_LIMIT;
            if(CalcT2 < NEXT_POINT_MIN_LIMIT)
                CalcT2 = NEXT_POINT_MIN_LIMIT;
        }
        IsFullOutMode = false;
    }
}

bool SoftPwmItem::Check()
{
    if(Port.IsNone() && PortN.IsNone()) //一个都没有
        return false;
    if(Period == 0)
        return false;
    // if(Duty == 0)
    //     return false;
    if(!IsFullOutMode)
    {
        if(CalcT1 < NEXT_POINT_MIN_LIMIT || 
           CalcT2 < NEXT_POINT_MIN_LIMIT)
            return false;
    }

    return true;
}

void SoftPwmItem::Begin()
{
    IsRunning = true;
    CurrentValue = (IsReverse)? !NormalValue:NormalValue;
}

void SoftPwmItem::End()
{
    IsRunning = false;
    CurrentValue = NormalValue;
    
    if(!Port.IsNone())
        SOC_Gpio::Write(Port, NormalValue);
    if(!PortN.IsNone())
        SOC_Gpio::Write(PortN, IsSameWhenNormal? NormalValue : !NormalValue);
}

int SoftPwmItem::Next()
{
    int nextValue = 0;
    
    if(IsFullOutMode)
    {
        nextValue = Period;
        CurrentValue = (Duty == 0)? 0:1;
        if(IsReverse)  
            CurrentValue = !CurrentValue;
        LastPoint = PointPostion::P2;
    }
    else
    {
        CurrentValue = !CurrentValue;
        nextValue = (CurrentValue)? CalcT1 : CalcT2;
        LastPoint = (CurrentValue)? PointPostion::P1:PointPostion::P2;
    }
    
    if(!Port.IsNone()) 
    {
        SOC_Gpio::Write(Port, CurrentValue);
    }

    if(!PortN.IsNone())
    {
        SOC_Gpio::Write(PortN, !CurrentValue);
    }

    return nextValue;
}
